import 'package:json_annotation/json_annotation.dart';
import 'package:logger/logger.dart';
import 'package:sqflite_common_ffi/sqflite_ffi.dart';

part 'LocalMessageRepository.g.dart';

class LocalMessageMessageSourceConstants {
  static const inbox = 1;
  static const outbox = 2;
}

class LocalMessageStatusConstants {
  /// 无效状态
  ///   outbox消息不需要在客户端管理状态，使用次状态作为默认值
  static const invalid = -1;

  /// 待发送
  static const readyToSend = 0;

  /// 已发送
  static const sent = 1;
}

class LocalMessageReadState {
  /// 未读
  static const unread = 0;

  /// 已读
  static const read = 1;
}

@JsonSerializable()
class LocalMessage {
  LocalMessage();

  LocalMessage.create(
      {this.localMsgId,
      this.conversationId,
      this.serverMsgId,
      this.sourceUserId,
      this.chatGroupId,
      this.targetUserId,
      this.chatType,
      this.messageType,
      this.message,
      this.sendTime,
      this.status,
      this.messageSource,
      this.readState});

  static LocalMessage fromJson(Map<String, dynamic> json) {
    return _$LocalMessageFromJson(json);
  }

  /// 本地消息ID
  int? localMsgId;

  /// 会话ID
  int? conversationId;

  /// 服务器消息ID
  int? serverMsgId;

  /// 消息来源用户ID
  int? sourceUserId;

  /// 消息目标用户ID
  int? targetUserId;

  /// 聊天群ID
  int? chatGroupId;

  /// 0 一对一聊天
  int? chatType;

  /// 消息类型 0 文本消息
  int? messageType;

  /// 消息内容
  String? message;

  /// 消息发送时间
  int? sendTime;

  /// 消息状态
  ///   inbox消息: 0 客户端待发送 1 发送成功
  ///   outbox消息： outbox消息不需要在客户端管理状态，使用 -1 作为默认值
  int? status;

  /// 消息来源 1 inbox消息 2 outbox消息
  int? messageSource;

  /// 已读状态 0 未读 1 已读
  int? readState = 0;

  Map<String, dynamic> toJson() {
    return _$LocalMessageToJson(this);
  }

  @override
  String toString() {
    return 'LocalMessage{localMsgId: $localMsgId, conversationId: $conversationId, serverMsgId: $serverMsgId, sourceUserId: $sourceUserId, targetUserId: $targetUserId, chatType: $chatType, messageType: $messageType, message: $message, sendTime: $sendTime, status: $status, messageSource: $messageSource, readState: $readState}';
  }
}

class LocalMessageRepository {
  static const String _tableName = "local_message";

  static Logger logger = Logger();

  static Future<void> addLocalMessage(
      Transaction transaction, LocalMessage message) async {
    message.localMsgId = await transaction.insert(_tableName, message.toJson());
  }

  static Future<void> completeMessageSending(
      Transaction transaction, int? id, int? sendTime) async {
    await transaction.update(_tableName,
        {"sendTime": sendTime, "status": LocalMessageStatusConstants.sent},
        where: "localMsgId = ?", whereArgs: [id]);
  }

  static Future<void> changeReadState2Read(
      Transaction transaction, int? id) async {
    if (id == null) {
      return;
    }
    await transaction.update(
        _tableName, {"readState": LocalMessageReadState.read},
        where: "localMsgId = ?", whereArgs: [id]);
  }

  static Future<void> changeAllMsgReadState2Read(
      Transaction transaction, int? conversationId) async {
    if (conversationId == null) {
      return;
    }
    await transaction.update(
        _tableName, {"readState": LocalMessageReadState.read},
        where: "conversationId = ?", whereArgs: [conversationId]);
  }

  static Future<Map<int, int>> getUnreadMsgCount(
      Transaction transaction, List<int> conversionIdList) async {
    Map<int, int> result = {};
    if (conversionIdList.isEmpty) {
      return result;
    }
    String conversionIdStr = "";
    for (var id in conversionIdList) {
      if (conversionIdStr.isEmpty) {
        conversionIdStr = "$id";
      } else {
        conversionIdStr = "$conversionIdStr, $id";
      }
    }
    for (var element in (await transaction.rawQuery("""
    select conversationId, count(conversationId) unreadMsgCount
    from local_message
    where conversationId in ($conversionIdStr)
      and readState = 0
    group by conversationId
    """))) {
      int? conversationId = element["conversationId"] as int?;
      int? unreadMsgCount = element["unreadMsgCount"] as int?;
      if (conversationId == null) {
        continue;
      }
      result[conversationId] = unreadMsgCount ?? 0;
    }
    return result;
  }

  static Future<List<LocalMessage>> queryNewLocalMsg(
      Transaction transaction, int msgCount, int conversationId) async {
    return (await transaction.query(_tableName,
            where: "conversationId = ?",
            whereArgs: [conversationId],
            limit: msgCount,
            orderBy: "localMsgId desc"))
        .map((json) {
      return LocalMessage.fromJson(json);
    }).toList();
  }

  static Future<void> deleteByLocalConversationID(
      Transaction transaction, int conversationId) async {
    await transaction.delete(_tableName,
        where: "conversationId = ?", whereArgs: [conversationId]);
  }
}
